//一条包含字母 A-Z 的消息通过以下方式进行了编码： 
//
// 'A' -> 1
//'B' -> 2
//...
//'Z' -> 26
// 
//
// 给定一个只包含数字的非空字符串，请计算解码方法的总数。 
//
// 示例 1: 
//
// 输入: "12"
//输出: 2
//解释: 它可以解码为 "AB"（1 2）或者 "L"（12）。
// 
//
// 示例 2: 
//
// 输入: "226"
//输出: 3
//解释: 它可以解码为 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) 。
// 
// Related Topics 字符串 动态规划 
// 👍 489 👎 0

package leetcode.editor.cn;

//Java：解码方法
public class P91DecodeWays {

    /**
     *
     * 思路：动态规划，可以联想到爬楼梯那一题，最后一个的方法就是 倒二的方法数 + 倒一的方法数。但是还要判断是不是有0，还有倒二两位数是不是可以用字母表示
     *
     * 执行用时： 1 ms , 在所有 Java 提交中击败了 99.98% 的用户 内存消耗： 38.1 MB , 在所有 Java 提交中击败了 34.04% 的用户
     *
     */
    //leetcode submit region begin(Prohibit modification and deletion)
    class Solution {
        public int numDecodings(String s) {
            if (s.length() == 0 || s.charAt(0) == '0') {
                return 0;
            }
            if (s.length() == 1) {
                return 1;
            }

            // dp[i] 指前 i+1 位有几种方法
            int[] dp = new int[s.length()];
            dp[0] = 1;

            boolean one = isValid(s, 0, 1);
            if (s.charAt(1) == '0') {
                dp[1] = one ? 1 : 0;
            }else{
                dp[1] = one ? 2 : 1;
            }

            for (int i = 2; i < s.length(); i++) {
                // 如果本位为0，那么如果前两位合法，那就是 dp[i] = dp[i - 2],不合法的话就是0了  例如：130，就是 0
                if (s.charAt(i) == '0') {
                    if (isValid(s, i - 1, i)) {
                        dp[i] = dp[i - 2];
                    } else {
                        return 0;
                    }
                } else {
                 // 本位不为0的话，如果前两位合法，就是 dp[i] = dp[i - 1] + dp[i - 2] ，例如 112， 不合法就是dp[i] = dp[i - 1]，例如 133
                    if (isValid(s, i - 1, i)) {
                        dp[i] = dp[i - 1] + dp[i - 2];
                    } else {
                        dp[i] = dp[i - 1];
                    }
                }
            }

            return dp[s.length() - 1];

        }

        // 是否有效  第i,j 位组成的是否可以有效解释
        private boolean isValid(String s, int i, int j) {
            if (s.charAt(i) == '1') {
                return true;
            }
            if (s.charAt(i) == '2') {
                return s.charAt(j) >= '0' && s.charAt(j) <= '6';
            }
            return false;
        }
    }
    //leetcode submit region end(Prohibit modification and deletion)

    public static void main(String[] args) {
        Solution solution = new P91DecodeWays().new Solution();
        System.out.println(solution.numDecodings("0"));
        System.out.println(solution.numDecodings("10"));
        System.out.println(solution.numDecodings("100"));
        System.out.println(solution.numDecodings("130"));
        // TO TEST
    }

}